package com.chiaching.framwork.core.feign;

import com.alibaba.fastjson.JSONObject;
import feign.Response;
import feign.codec.Decoder;
import org.apache.commons.io.IOUtils;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class DefaultDecoder implements Decoder {

    private final static Map<Type, ParameterizedTypeImpl> TYPE_PARAMETERIZED_CACHE = new HashMap<>();

    private final static Object LOCK = new Object();

    @Override
    public Object decode(Response response, Type type) {
        if (response.body() == null) return null;
        ResponseEntity responseEntity;
        ParameterizedTypeImpl parameterizedType = this.getParameterizedType(type);
        String content = null;
        try {
            InputStream inputStream = response.body().asInputStream();
            content = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
            responseEntity = doDecode(content, parameterizedType);
        } catch (Exception e) {
            throw new ApiAccessException(response.request().url(), content, e);
        }
        if (responseEntity == null) {
            throw new ApiAccessException(response.request().url(), "");
        } else if (!"200".equals(responseEntity.getRetCode())) {
            throw new ApiAccessException(response.request().url(), responseEntity);
        }
        return responseEntity.getRetData();
    }

    private ParameterizedTypeImpl getParameterizedType(Type type) {
        ParameterizedTypeImpl parameterizedType = TYPE_PARAMETERIZED_CACHE.get(type);
        if (parameterizedType == null) {
            synchronized (LOCK) {
                parameterizedType = TYPE_PARAMETERIZED_CACHE.get(type); //double check here
                if (parameterizedType == null) {
                    parameterizedType = ParameterizedTypeImpl.make(ResponseEntity.class, new Type[]{type}, null);
                    TYPE_PARAMETERIZED_CACHE.put(type, parameterizedType);
                }
            }
        }
        return parameterizedType;
    }

    private ResponseEntity doDecode(String content, ParameterizedTypeImpl parameterizedType) throws Exception {
        return JSONObject.parseObject(content, parameterizedType);
    }

    static class ResponseEntity<T> {

        static final ResponseEntity EMPTY = new ResponseEntity();

        private String retCode;

        private T retData;

        private String retMesg;

        public String getRetCode() {
            return retCode;
        }

        public void setRetCode(String retCode) {
            this.retCode = retCode;
        }

        public T getRetData() {
            return retData;
        }

        public void setRetData(T retData) {
            this.retData = retData;
        }

        public String getRetMesg() {
            return retMesg;
        }

        public void setRetMesg(String retMesg) {
            this.retMesg = retMesg;
        }
    }
}